/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.portlet.editor.gui.view.settings.panel.portlet;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.TableModelEvent;

import com.genia.toolbox.basics.editor.gui.AbstractGUI;
import com.genia.toolbox.basics.editor.model.document.VariableModel;
import com.genia.toolbox.portlet.editor.gui.PortletEditorGUI;
import com.genia.toolbox.portlet.editor.gui.view.settings.panel.PortletSettingsPanel;
import com.genia.toolbox.portlet.editor.gui.view.settings.table.VariableCellEditor;
import com.genia.toolbox.portlet.editor.gui.view.settings.table.VariableCellRenderer;
import com.genia.toolbox.portlet.editor.gui.view.settings.table.VariableTableModel;
import com.genia.toolbox.portlet.editor.model.portlet.impl.PortletModel;

/**
 * Abstract settings panel.
 */
@SuppressWarnings("serial")
public abstract class AbstractPortletSettingsPanel
    extends JPanel
    implements PortletSettingsPanel
{

  /**
   * The application portletEditorGUI.
   */
  private PortletEditorGUI portletEditorGUI;

  /**
   * The displayed portlet model.
   */
  private PortletModel model = null;

  /**
   * The specific panel.
   */
  private JPanel specificPanel = null;

  /**
   * The ID label.
   */
  private JLabel labelId = null;

  /**
   * The ID text field.
   */
  protected JTextField textId = null;

  /**
   * The portlet name label.
   */
  private JLabel labelPortletName = null;

  /**
   * The portlet name text field.
   */
  protected JTextField textPortletName = null;

  /**
   * The description label.
   */
  private JLabel labelDescription = null;

  /**
   * The description text field.
   */
  protected JTextArea areaDescription = null;

  /**
   * The attribute label.
   */
  private JLabel labelAttribute = null;

  /**
   * The attribute field.
   */
  private JLabel labelAttributeName = null;

  /**
   * The attribute name label.
   */
  private JTextField textAttributeName = null;

  /**
   * The add attribute button.
   */
  private JButton buttonAddAttribute = null;

  /**
   * The delete attribute button.
   */
  private JButton buttonDeleteSelectedAttribute = null;

  /**
   * The attributes table.
   */
  private JTable tableAttributes = null;

  /**
   * The table attributes model.
   */
  private VariableTableModel tableAttributesModel = null;



  /**
   * Constructor.
   * 
   * @param portletEditorGUI
   *          the application portletEditorGUI.
   */
  public AbstractPortletSettingsPanel(PortletEditorGUI portletEditorGUI)
  {
    super();
    this.portletEditorGUI = portletEditorGUI;
  }



  /**
   * Initialise the panel.
   */
  public void initialise()
  {

    GridBagLayout layout = new GridBagLayout();
    GridBagConstraints constraints = new GridBagConstraints();
    this.setLayout(layout);

    constraints.gridx = 1;
    constraints.gridy = 1;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(5, 5, 5, 5);
    this.add(this.createCommonSettingsPanel(), constraints);

    this.specificPanel = this.createSpecificPanel();
    this.specificPanel.setBorder(BorderFactory.createTitledBorder(this.portletEditorGUI.getController().notifyTranslation(
        "com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.specific.border.title")));
    constraints.gridx = 1;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 1;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.insets = new Insets(0, 5, 5, 5);
    this.add(this.specificPanel, constraints);

  }



  /**
   * Create the specific panel.
   * 
   * @return the specific panel.
   */
  public abstract JPanel createSpecificPanel();



  /**
   * Create the common panel.
   * 
   * @return the common panel.
   */
  public JPanel createCommonSettingsPanel()
  {
    JPanel panel = new JPanel();

    GridBagLayout layout = new GridBagLayout();
    GridBagConstraints constraints = new GridBagConstraints();
    panel.setLayout(layout);

    panel.setBorder(BorderFactory.createTitledBorder(this.portletEditorGUI.getController().notifyTranslation(
        "com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.common.border.title")));

    this.labelPortletName = new JLabel(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.PortletName"));
    constraints.gridx = 1;
    constraints.gridy = 1;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(0, 0, 0, 0);
    panel.add(this.labelPortletName, constraints);

    this.textPortletName = new JTextField();
    this.textPortletName.setEditable(false);
    constraints.gridx = 2;
    constraints.gridy = 1;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(0, 5, 0, 0);
    panel.add(this.textPortletName, constraints);

    this.labelDescription = new JLabel(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Description"));
    this.labelDescription.setVerticalTextPosition(SwingConstants.TOP);
    this.labelDescription.setVerticalAlignment(SwingConstants.TOP);
    constraints.gridx = 1;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 3;
    constraints.weightx = 0;
    constraints.weighty = 1;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.anchor = GridBagConstraints.NORTH;
    constraints.insets = new Insets(5, 0, 30, 0);
    panel.add(this.labelDescription, constraints);

    this.areaDescription = new JTextArea();
    this.areaDescription.setLineWrap(true);
    this.areaDescription.setWrapStyleWord(true);
    this.areaDescription.setFont(this.labelDescription.getFont());
    this.areaDescription.setEditable(false);
    constraints.gridx = 2;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 3;
    constraints.weightx = 1;
    constraints.weighty = 1;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.insets = new Insets(5, 5, 0, 0);
    panel.add(this.areaDescription, constraints);

    this.labelId = new JLabel(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Id"));
    constraints.gridx = 1;
    constraints.gridy = 5;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(5, 0, 0, 0);
    panel.add(this.labelId, constraints);

    this.textId = new JTextField();
    this.textId.getDocument().addDocumentListener(this);
    constraints.gridx = 2;
    constraints.gridy = 5;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(5, 5, 0, 0);
    panel.add(this.textId, constraints);

    return panel;
  }



  /**
   * Create the attributes settings panel.
   * 
   * @return the attributes settings panel.
   */
  public JPanel createAttributesSettingsPanel()
  {
    JPanel panel = new JPanel();

    GridBagLayout layout = new GridBagLayout();
    GridBagConstraints constraints = new GridBagConstraints();
    panel.setLayout(layout);

    this.labelAttribute = new JLabel(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Attribute"));
    constraints.gridx = 1;
    constraints.gridy = 1;
    constraints.gridwidth = 3;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(0, 0, 0, 0);
    panel.add(this.labelAttribute, constraints);

    this.labelAttributeName = new JLabel(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.AttributeName"));
    constraints.gridx = 1;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(5, 15, 0, 0);
    panel.add(this.labelAttributeName, constraints);

    this.textAttributeName = new JTextField();
    constraints.gridx = 2;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.insets = new Insets(5, 5, 0, 0);
    panel.add(this.textAttributeName, constraints);

    this.buttonAddAttribute = new JButton(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.AddAttribute"));
    this.buttonAddAttribute.addActionListener(this);
    constraints.gridx = 3;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.NONE;
    constraints.insets = new Insets(5, 5, 0, 0);
    panel.add(this.buttonAddAttribute, constraints);

    String[] columnNames = new String[] { this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.AttributeTableName"),
        this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.AttributeTableValue") };
    this.tableAttributesModel = new VariableTableModel(columnNames);
    this.tableAttributesModel.addTableModelListener(this);
    this.tableAttributes = new JTable(this.tableAttributesModel);
    this.tableAttributes.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    VariableCellRenderer cellRenderer = new VariableCellRenderer(this.getGui());
    VariableCellEditor cellEditor = new VariableCellEditor(this.getGui());
    this.tableAttributes.getColumnModel().getColumn(0).setCellRenderer(cellRenderer);
    this.tableAttributes.getColumnModel().getColumn(1).setCellRenderer(cellRenderer);
    this.tableAttributes.getColumnModel().getColumn(0).setCellEditor(cellEditor);
    this.tableAttributes.getColumnModel().getColumn(1).setCellEditor(cellEditor);
    this.tableAttributes.setRowHeight(25);
    JScrollPane scrollpane = new JScrollPane(this.tableAttributes);
    constraints.gridx = 1;
    constraints.gridy = 3;
    constraints.gridwidth = 3;
    constraints.gridheight = 1;
    constraints.weightx = 1;
    constraints.weighty = 1;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.insets = new Insets(5, 15, 0, 0);
    panel.add(scrollpane, constraints);

    this.buttonDeleteSelectedAttribute = new JButton(this.portletEditorGUI.getController().notifyTranslation(
        "com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.buttonDeleteSelectedAttributes"));
    this.buttonDeleteSelectedAttribute.addActionListener(this);
    constraints.gridx = 1;
    constraints.gridy = 4;
    constraints.gridwidth = 3;
    constraints.gridheight = 1;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.NONE;
    constraints.anchor = GridBagConstraints.EAST;
    constraints.insets = new Insets(5, 0, 0, 0);
    panel.add(this.buttonDeleteSelectedAttribute, constraints);

    return panel;
  }



  /**
   * Hide the identifier.
   */
  public void hideIdentifier()
  {
    this.labelId.setVisible(false);
    this.textId.setVisible(false);
  }



  /**
   * Show the identifier.
   */
  public void showIdentifier()
  {
    this.labelId.setVisible(true);
    this.textId.setVisible(true);
  }



  /**
   * Handle the action event.
   * 
   * @param e
   *          the action event.
   */
  public void actionPerformed(ActionEvent e)
  {
    Object source = e.getSource();
    if (source.equals(this.buttonAddAttribute)) {
      String name = this.textAttributeName.getText();
      boolean alreadyExists = false;
      for (VariableModel variable : this.tableAttributesModel.getVariables()) {
        if (variable.getName().equals(name)) {
          alreadyExists = true;
        }
      }
      if (!alreadyExists) {
        if (name != null && name.trim().length() > 0) {
          this.tableAttributesModel.addVariable(new VariableModel(name, ""));
        }
        this.textAttributeName.setText("");
      }
      else {
        this.portletEditorGUI.tell(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Attribute.Error.Title"),
            this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Attribute.Error.Message"));
        this.textAttributeName.setText("");
      }
    }
    else if (source.equals(this.buttonDeleteSelectedAttribute)) {
      int row = this.tableAttributes.getSelectedRow();
      if (row != -1) {
        VariableModel variable = this.tableAttributesModel.getValueAt(row);
        if (variable != null && !variable.isMandatory()) {
          if (this.portletEditorGUI.ask(this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Attribute.Title"),
              this.portletEditorGUI.getController().notifyTranslation("com.genia.toolbox.portlet.editor.gui.panel.portlets.BasicPortletSettingsPanel.Attribute.Message"))) {
            this.tableAttributesModel.removeVariable(variable);
          }
        }
      }
    }
  }



  /**
   * Set the displayed portlet.
   * 
   * @param model
   *          the portlet model.
   */
  public void setPortlet(PortletModel model)
  {
    this.showIdentifier();
    this.model = model;
    this.textId.setText(model.getId());
    this.textPortletName.setText(model.getElementName());
    this.validateSettings();
  }



  /**
   * Initialise the attributes.
   * 
   * @param variables
   *          the attributes variables.
   */
  public void initialiseAttributes(List<VariableModel> variables)
  {
    this.textAttributeName.setText("");
    this.tableAttributesModel.clear();
    if (variables != null) {
      for (VariableModel variable : variables) {
        this.tableAttributesModel.addVariable(variable);
      }
    }
  }



  /**
   * The application PortletEditorGUI.
   * 
   * @return the application PortletEditorGUI.
   */
  public PortletEditorGUI getGui()
  {
    return this.portletEditorGUI;
  }



  /**
   * The displayed portlet model.
   * 
   * @return the displayed portlet model.
   */
  public PortletModel getPortlet()
  {
    PortletModel updatedModel = this.model;
    updatedModel.setId(this.textId.getText());
    return updatedModel;
  }



  /**
   * Remove all listeners.
   */
  public void removeAllListeners()
  {
    this.textId.getDocument().removeDocumentListener(this);
    if (this.tableAttributesModel != null) {
      this.tableAttributesModel.removeTableModelListener(this);
    }
  }



  /**
   * Add all listeners.
   */
  public void addAllListeners()
  {
    this.textId.getDocument().addDocumentListener(this);
    if (this.tableAttributesModel != null) {
      this.tableAttributesModel.addTableModelListener(this);
    }
  }



  /**
   * Get the updated attributes.
   * 
   * @return the updated attributes.
   */
  public List<VariableModel> getUpdatedAttributes()
  {
    List<VariableModel> attributes = new ArrayList<VariableModel>();
    int rows = this.tableAttributes.getRowCount();
    VariableModel variable = null;
    for (int row = 0; row < rows; row++) {
      variable = this.tableAttributesModel.getValueAt(row);
      if (variable != null) {
        attributes.add(variable);
      }
    }
    return attributes;
  }



  /**
   * Handle the change document events.
   * 
   * @param e
   *          the document event.
   */
  public void changedUpdate(DocumentEvent e)
  {
    // Do nothing.
  }



  /**
   * Handle the insert document events.
   * 
   * @param e
   *          the document event.
   */
  public void insertUpdate(DocumentEvent e)
  {
    this.validateSettings();
    this.getGui().notifyDocumentSettingsHasToBeSaved();
    this.getGui().notifyElementSettingsChanged(this.getPortlet());
  }



  /**
   * Handle the remove document events.
   * 
   * @param e
   *          the document event.
   */
  public void removeUpdate(DocumentEvent e)
  {
    this.validateSettings();
    this.getGui().notifyDocumentSettingsHasToBeSaved();
    this.getGui().notifyElementSettingsChanged(this.getPortlet());
  }



  /**
   * Handle the table change events.
   * 
   * @param e
   *          the table event.
   */
  public void tableChanged(TableModelEvent e)
  {
    this.validateSettings();
    this.getGui().notifyDocumentSettingsHasToBeSaved();
    this.getGui().notifyElementSettingsChanged(this.getPortlet());
  }



  /**
   * Check whether the settings are valid.
   */
  public void validateSettings()
  {
    if (this.textId.getText() == null || this.textId.getText().trim().length() == 0) {
      this.labelId.setForeground(AbstractGUI.COLOR_TEXT_ERROR);
    }
    else {
      this.labelId.setForeground(AbstractGUI.COLOR_TEXT);
    }
  }



  /**
   * Get the ID text field.
   * 
   * @return the ID text field.
   */
  public JTextField getTextId()
  {
    return this.textId;
  }



  /**
   * Get the specific panel.
   * 
   * @return the specific panel.
   */
  public JPanel getSpecificPanel()
  {
    return this.specificPanel;
  }

}
